/**
 * 原型链继承，若此时实例没有此属性或方法，它会找他的构造函数原型对象...
 */
function Person1(){

}
Person1.prototype.say = function(){
    console.log("say");
}
let obj1 = {};
Object.setPrototypeOf(obj1,Person1.prototype);
obj1.say();

/**
 * 借用构造函数
 * 主要是在子类型的构造函数中调用父类型的构造函数
 */
function SuperType1(){
    this.name = "hhh";
}
function SubType1(){
    SuperType1.call(this);
    this.age = 18;
}
let sub = new SubType1();
console.log(sub.name);


/**
 * 组合继承
 * 这种方法的主要思路是使用原型链实现对原型属性和方法的继承，而通过借用构造函数来实现对实例属性的继承。
 * 这样既通过在原型上定义方法实现了函数复用，又能够保证每个实例都有它自己的属性
 */
function SuperType2(name){
    this.name = name;
}
SuperType2.prototype.sayName = function(){
    console.log(this.name);
}
function SubType2(name,age){
    SuperType2.call(this,name);
    this.age = age;
}
SubType2.prototype.sayAge = function(){
    console.log(this.age);
}

//当找不到SubType2.prototype这个上面的属性时，去找SuperType2.prototype这个上面的属性
Object.setPrototypeOf(SubType2.prototype,SuperType2.prototype)
//表示将SuperType2.prototype作为SubType2.prototype的原型对象
let sub2 = new SubType2("ruran",23);
sub2.sayName();
sub2.sayAge();

/**
 * 原型式继承
 * 原型式继承的主要思路是可以基于已有的对象创建新的对象，同时还不必因此创建自定义类型。如下面的例子所示
 * 基于传进来的一个对象，此时将这个对象作为返回对象的原型对象
 */
function object(obj){
    function Fn(){};
    Fn.prototype = obj;
    return new Fn();
}
//简单来说这个函数的作用就是，传入一个对象，返回一个原型对象为该对象的新对象。

/**
 * 寄生式继承
 * 创建一个仅用于封装继承过程的函数，该函数在内部以某种方式增强对象，最后返回这个对象。
 */

 function createAnother(obj){
    let newObj = object(obj);
    newObj.sayIt = function(){
        console.log("sayIt");
    }
    return newObj;
 }
 let person = {
     name:"ruran",
     age:23
 }
 let newObj = createAnother(person);
 newObj.sayIt();

 /**
  * 寄生式组合继承
  * 它与组合继承不同的地方主要是，在继承原型时，我们继承的不是超类的实例对象，
  * 而是原型对象是超类原型对象的一个实例对象，这样就解决了基类的原型对象中增添了不必要的超类的实例对象中的所有属性d的问题。
  */

  function inheritPrototype(subtype,supertype){
      let clone = object(supertype.prototype);
      clone.constructor = subtype;
      subtype.prototype = clone;
  }
//优点：效率高，避免了在 SubType.prototype 上创建不必要的属性。与此同时还能保持原型链不变，开发人员普遍认为寄生组合式继承是引用类型最理想的继承范式。
